﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


using System.Reflection; //反射需要使用的命名空间

namespace CSharpInterfaceTeach
{
    ///一：接口
    /// <summary>
    /// 接口目的：
    /// 1.为了更好的实现扩展
    /// 2.方便团队开发
    /// 
    /// 规范：接口就是没有方法体的方法声明(没有修饰访问修饰符的方法签名)
    /// 特点：具有强制性。一个类实现了一个接口就必须把接口里面的方法都要实现
    /// 
    /// 使用场景：如果一个类同时实现若干接口类，但是这接口类中如果有相同名称的接口，这时候你想多次实现相同名称的接口，这时候我们必须“显示实现接口”防止同名方法的冲突
    /// 
    /// 
    /// 
    /// 第一个案例启发：接口设计者根据需求设计接口，然后由其他人去实现接口
    /// 
    /// 
    /// 
    /// 
    /// 
    /// 二:接口多态
    /// 1.基于接口编程
    /// 要求：使用接口作为变量，用“实现类对象”赋值
    /// 
    /// 注意：基于接口编程，接口变量只能使用接口类中规定的方法，接口实现类自己的方法是不能调用的
    /// 
    /// 好处1：可以轻松的实现团队的“并行开发”
    /// 好处2：如果接口的实现类变化，对于整个程序的影响是最小的
    /// 
    /// 
    /// 2.接口多态
    /// 【1】接口作为方法的返回值类型,实际上方法返回的是具体“实现类对象”
    /// 好处：基于接口编程无需关系接口具体得到的是哪个实现类的对象，达到“解耦”
    /// 
    /// 
    /// 【2】接口作为方法的参数类型，实际上调用方法传递的是具体“实现类的对象”
    /// 
    /// 
    /// 
    /// 三：反射技术
    /// 1.概念：通过使用一个“程序集”，把我们要使用的类的命名空间、类名，通过“字符串”方式，使用反射技术，从而得到这个类的对象
    /// 记住：我们想使用一个类的对象，不见得非要通过直接new的方式，也可以通过“反射”方式得到
    /// 
    /// 2.使用
    /// 【1】引入命名空间： using System.Reflection
    /// 【2】使用程序集类：Assemby
    /// 【3】反射结果为接口类型，实现解耦
    /// 
    /// 如果开发中确实需要扩展同一个接口的类的实现，请使用工厂讲解的对象工厂创建对象的方法，达到“完全解耦”的目的
    /// 
    /// 
    /// 
    /// 四：基于类库使用反射技术
    /// 补充（将要反射的类放到其他的类库中）
    /// 
    /// 
    /// 
    /// 
    /// 四、接口和继承同时使用
    /// 1.一个类可以实现多个接口，接口后面都用逗号分割
    /// 
    /// 2.一个类同时继承一个类，同时也实现接口，要求把继承的类放到前面，后面用逗号分割其他的接口
    /// 
    /// 通常说：继承一个类，实现一个接口
    /// 应用：通常是直接使用子类对象，而不是用接口
    /// </summary>
    internal class Program
    {
        static void Main(string[] args)
        {
            Test1();
            Console.WriteLine("---------------------------");
            Test2();
            Console.WriteLine("---------------------------");
            Test3();
            Console.WriteLine("---------------------------");
            Test4();
            Console.WriteLine("---------------------------");
            Test5();
            Console.WriteLine("---------------------------");
            Test6();

            Console.ReadLine();
        }

        //接口实现类的普通使用方式
        static void Test1()
        {
            EquipOperationImpl equipOperationImpl = new EquipOperationImpl();
            equipOperationImpl.Start("10000");
            equipOperationImpl.Accelerate();
            equipOperationImpl.SlowDown();
            equipOperationImpl.Stop();

            equipOperationImpl.ReStart();
        }

        static void Test2()
        {
            IEquipOperation equipOperationImpl = new EquipOperationImplNew();
            equipOperationImpl.Start("10000");
            equipOperationImpl.Accelerate();
            equipOperationImpl.SlowDown();
            equipOperationImpl.Stop();
        }

        static void Test3()
        {
            //接口多态：接口作为方法返回值类型
            IEquipOperation equipOperation = Operate(2);
            equipOperation.Start("10000");
            equipOperation.Accelerate();
            equipOperation.SlowDown();
            equipOperation.Stop();
        }

        static void Test4()
        {
            Operate(new EquipOperationImpl());

            Operate(new EquipOperationImplNew());
        }

        /// <summary>
        /// 接口作为方法的返回值类型
        /// </summary>
        /// <param name="no"></param>
        /// <returns></returns>
        static IEquipOperation Operate(int no)
        {
            //在这个地方添加逻辑
            if(no == 1)
            {
                return new EquipOperationImpl();
            }
            else
            {
                return new EquipOperationImplNew();
            }
        }

        /// <summary>
        /// 接口作为方法的参数
        /// </summary>
        /// <param name="equipOperation"></param>
        static void Operate(IEquipOperation equipOperation)
        {
            equipOperation.Start("10000");
            bool res = equipOperation.Accelerate();
            Console.WriteLine(res);
            equipOperation.SlowDown();
            equipOperation.Stop();
        }

        static void Test5()
        {
            IEquipOperation equipOperation = (IEquipOperation)Assembly.Load("CSharpInterfaceTeach").CreateInstance("CSharpInterfaceTeach.EquipOperationImpl");

            equipOperation.Start("10005");
            bool res = equipOperation.Accelerate();
            Console.WriteLine(res);
            equipOperation.SlowDown();
            equipOperation.Stop();
        }


        //使用反射对象工厂类得到对象（完全解耦）
        static void Test6()
        {
            //这种方式完全不用关心对象是如何创建的
            IEquipOperation equipOperation = ObjectFactory.GetOperation();

            equipOperation.Start("10006");
            bool res = equipOperation.Accelerate();
            Console.WriteLine(res);
            equipOperation.SlowDown();
            equipOperation.Stop();
        }

        public void Test7()
        {
            //通过子类对象的使用，可以实现全部成员的调用
            EquipOperationImpl equipOperationImpl = new EquipOperationImpl();
            equipOperationImpl.EquipId = 1;

            //通过接口使用会把子类对象限制在接口规定的方法内
            IEquipOperation impl2 = new EquipOperationImpl();
            impl2.Start("1008");

            //如果使用父类类型，则所有的接口实现都将屏蔽
            Equip equip = new EquipOperationImpl();
            equip.EquipId = 20001;
        }
    }
}
